#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

from cmds import *
from net import *
from card import *
from config import INI

class Player(object):
    '''玩家类，响应服务器指令，对应的操作（网络或本地的操作数据）'''
    def __init__(self, info={}):
        #玩家的个人信息，包括座位号id、玩家名字name等
        self.info={}
        self.setInfo(info)
        #玩家的持牌列表
        self.cardList=[]
        #玩家的出牌缓冲
        self.outBuf=None
        #玩家的准备状态
        self.ready=False
        #玩家可视的游戏数据，包括各玩家的牌数、游戏积分、出牌队列等
        self.gameData={}

    def updateConfig(self):
        '''从配置文件更新配置'''
        pass

    def setInfo(self, info):
        '''设置玩家信息'''
        for k, v in info.iteritems():
            self.info[k]=v

    def setReady(self, on=True):
        '''设置准备状态'''
        self.ready=on

    def resetData(self):
        '''重置游戏数据为初始状态，不重置info'''
        self.cardList=[]
        self.outList=[]
        self.gameData={}

    def updateGameData(self, data):
        '''更新游戏数据'''
        for k, v in data.iteritems():
            self.gameData[k]=v

    def do(self, cmd, data=[]):
        '''将命令数据翻译成对应操作，并返回结果'''
        try:
            if cmd==TAKECARD:
                return self.takeCard(data)
            elif cmd==PLAYCARD:
                return self.playCard(data)
            elif cmd==SHOWCARD:
                return self.showCard(data)
            elif cmd==UNDO:
                self.undo(data)
            elif cmd==EXCHANGEINFO:
                return self.exchangeInfo(data)
            elif cmd==UPDATEDATA:
                self.updateData(data)
            elif cmd==RESETDATA:
                self.resetData()
            elif cmd==GETREADY:
                return self.getReady()
            elif cmd==CHECK:
                return
            elif cmd==EXIT:
                raise Exception('Exit!')
            else:
                raise Exception('Error command!')
        except Exception, e:
            import sys, traceback
            traceback.print_exc()
#            self.setReady(False)
            return
    
    def takeCard(self, cards):
        '''摸牌'''
        self.cardList+=cards
        return TAKECARD, []
    
    def playCard(self, cards):
        '''出牌'''
        #更新持牌列表和出牌列表
        for card in cards:
            self.cardList.remove(card)
        #出牌到出牌缓冲
        self.outBuf=cards
        return PLAYCARD, cards

    def showCard(self, cards):
        '''亮牌'''
        #出牌到出牌缓冲
        self.outBuf=cards
        return SHOWCARD, cards

    def undo(self, uncmd):
        '''撤销之前的操作（撤销出牌、亮牌、给牌等）'''
        #从出牌缓冲撤销牌
        cards=self.outBuf
        self.outBuf=None
        #如果撤销的是出牌命令还要还原出牌
        if uncmd==PLAYCARD:
            self.cardList+=cards
        return

    def exchangeInfo(self, info):
        '''从服务器交换信息，如名字、id号等'''
        pass

    def updateData(self, data):
        '''更新数据'''
        pass
            
    def getReady(self):
        '''获得准备状态'''
        return GETREADY, self.ready


class LocalPlayer(Player):
    '''本地玩家，从用户界面获得操作数据'''
    def __init__(self, info={}):
        super(LocalPlayer, self).__init__(info)
        #连接的游戏人工智能对象
        self.ai=None
        #连接的界面对象
        self.ui=None
        #是否打开Ai（自动出牌）
        self.useAi=INI.player.initUseAi
        #是否打开准备状态
        self.ready=INI.player.initReady
        #AI动作延时
        self.aiTime=INI.player.aiTime/1000.0
        #摸牌延时
        self.takeTime=INI.player.takeTime/1000.0
        #更新设置
        self.updateConfig()

    def updateConfig(self):
        '''从配置文件更新配置'''
        #设置姓名
        self.setInfo({'name':INI.player.name})
        #设置AI动作延时
        self.aiTime=INI.player.aiTime/1000.0
        #设置摸牌延时
        self.takeTime=INI.player.takeTime/1000.0

    def setReady(self, on=True):
        '''设置准备状态'''
        self.ready=on
        if self.ui:
            self.ui.updateToolState()

    def setUseAI(self, on=True):
        '''设置是否打开Ai'''
        self.useAi=on
        if self.ui:
            self.ui.updateToolState()

    def setAI(self, ai):
        '''连接人工智能'''
        self.ai=ai
        self.ai.player=self

    def setUI(self, ui):
        '''连接界面'''
        self.ui=ui
        self.ui.player=self
        
        #更新UI的准备状态等按钮
        self.ui.updateToolState()
        
    def resetData(self):
        '''重置游戏数据为初始状态，需重置游戏AI'''
        super(LocalPlayer, self).resetData()
        if self.ui:
            self.ui.resetData()
        self.ai=None
    
    def updateGameData(self, data):
        '''更新游戏数据，初始时需设置AI'''
        super(LocalPlayer, self).updateGameData(data)
        if not self.ai:
            mGameName=self.gameData['mGameName']
            mGameName='games.'+mGameName
            __import__(mGameName)
            import sys
            mGame=sys.modules[mGameName]
            self.setAI(mGame.AI())
            self.ai.initData()
    
    def takeCard(self, cards):
        '''摸牌'''
        super(LocalPlayer, self).takeCard(cards)
        #更新UI的持牌数据
        if self.ui:
            self.ui.updateData(ADDCARD, cards)
        #摸牌延时
        time.sleep(self.takeTime)
        return TAKECARD, []
    
    def playCard(self, cards):
        '''出牌'''
        cards=[]
        if self.useAi:
            cards=self.ai.playCard()
            #AI延时
            time.sleep(self.aiTime)
        else:
            #从UI获得出牌数据
            cards=self.ui.getCardFromUser(u'请选择要出的牌：')
        return super(LocalPlayer, self).playCard(cards)

    def showCard(self, cards):
        '''亮牌'''
        cards=[]
        if self.useAi:
            cards=self.ai.showCard()
            #AI延时
            time.sleep(self.aiTime)
        else:
            #从UI获得出牌数据
            cards=self.ui.getCardFromUser(u'请选择要亮的牌：')
        return super(LocalPlayer, self).showCard(cards)

    def undo(self, uncmd):
        '''撤销操作（不符合规则，这里暂时实现撤牌）'''
        super(LocalPlayer, self).undo(uncmd)
        if self.ui:
            self.ui.updateData(SHOWMESSAGE, 'Illeagal card!')
        return
    
    def exchangeInfo(self, info):
        '''从服务器交换信息，这里从服务器获得id号，再将名字返回给服务器'''
        self.setInfo(info)
        if not self.info.get('name'):
            name='Bot_%d'%self.info['id']
            self.info['name']=name
        return EXCHANGEINFO, {'name':self.info['name']}
    
    def updateData(self, data):
        '''更新游戏数据
        data格式：操作者 操作指令 [操作数据]
        操作者可以是某个玩家，以id来表示
        '''
        op=data[0]
        cmd=data[1]
        cmddata=[]
        if len(data)>2:
            cmddata=data[2]
            
        #TODO:test data
        if cmd==SETGAMEDATA:
            self.updateGameData(cmddata)
            self.ui.updateData(cmd, cmddata)
        elif cmd==UPDATEGAMEDATA:
            self.updateGameData(cmddata)
            self.ui.updateData(cmd, cmddata)
        elif cmd==CLEAROUTLIST:
            self.ui.updateData(cmd, cmddata)
        #TODO:drop enter cmd later
        elif cmd==ENTER:
            self.ui.updateData(SHOWMESSAGE, 'Player %d: %s enter'%(op, cmddata['name']))
        elif cmd==TAKECARD:
#            self.ui.updateData(SHOWMESSAGE, 'Player %d take card'%op)
            self.ui.updateData(cmd, op)
        elif cmd==PLAYCARD:
            scards=[str(Card(cardid)) for cardid in cmddata]
            self.ui.updateData(SHOWMESSAGE, 'Player %d play: %s'%(op, str(scards)))
            self.ui.updateData(cmd, [op, cmddata])
        elif cmd==SHOWCARD:
            scards=[str(Card(cardid)) for cardid in cmddata]
            self.ui.updateData(SHOWMESSAGE, 'Player %d show: %s'%(op, str(scards)))
            self.ui.updateData(cmd, [op, cmddata])
        elif cmd==WIN:
            self.ui.updateData(SHOWMESSAGE, 'Player %d win!'%op)
            self.ui.updateData(cmd, op)
            #结束后取消准备
            self.setReady(False)
        elif cmd==SHOWMESSAGE:
            self.ui.updateData(SHOWMESSAGE, cmddata)
        return


class BotPlayer(LocalPlayer):
    '''机器人玩家，生成操作数据'''
    def __init__(self, info={}):
        super(BotPlayer, self).__init__(info)
        self.setReady()
        self.setUseAI()

    def updateConfig(self):
        '''从配置文件更新配置'''
        #设置AI动作延时
        self.aiTime=INI.player.aiTime/1000.0
        #设置摸牌延时
        self.takeTime=INI.player.takeTime/1000.0
    
    def updateData(self, data):
        '''更新游戏数据
        data格式：操作者 操作指令 [操作数据]
        操作者可以是某个玩家，以id来表示
        '''
        op=data[0]
        cmd=data[1]
        cmddata=[]
        if len(data)>2:
            cmddata=data[2]
        #TODO:test data
        if cmd==SETGAMEDATA:
            self.updateGameData(cmddata)
        elif cmd==UPDATEGAMEDATA:
            self.updateGameData(cmddata)
        return


class NetPlayer(Player):
    '''网络玩家，从网络获取操作数据'''
    def __init__(self, info={}):
        super(NetPlayer, self).__init__(info)
        #传输网络数据的套接字
        self.socket=None
    
    def checkConnected(self):
        '''检测连接状态'''
        try:
            self.socket.send(CHECK)
        except:
            return False
        return True
    
    def setSocket(self, sock):
        '''设置套接字，使用Socket类包装'''
        self.socket=Socket(sock)
    
    def getReady(self):
        '''从客户端获得准备状态'''
        cmd=GETREADY
        try:
            self.socket.send(GETREADY)
            cmd, ready=self.socket.recv()
            self.ready=ready
        except:
            self.ready=False
        return cmd, self.ready
        
    def takeCard(self, cards):
        '''摸牌，转发摸牌命令和牌数据到远程客户端，返回摸牌是否成功'''
        self.socket.send(TAKECARD, cards)
        cmd, data=self.socket.recv()
        self.cardList+=cards
        return cmd, data
    
    def showCard(self, cards):
        '''亮牌，转发摸牌命令和牌数据到远程客户端，返回摸牌是否成功'''
        self.socket.send(SHOWCARD)
        cmd, cards=self.socket.recv()
        super(NetPlayer, self).showCard(cards)
        return cmd, cards
    
    def playCard(self, cards):
        '''出牌，转发出牌命令到远程客户端，返回远端出的牌'''
        self.socket.send(PLAYCARD)
        cmd, cards=self.socket.recv()
        super(NetPlayer, self).playCard(cards)
        return cmd, cards
    
    def undo(self, uncmd):
        '''转发撤销命令到远程客户端，无返回'''
        self.socket.send(UNDO, uncmd)
        super(NetPlayer, self).undo(uncmd)
        return
    
    def exchangeInfo(self, info):
        '''从服务器交换信息，这里从服务器获得id号，再将名字返回给服务器'''
        self.setInfo(info)
        self.socket.send(EXCHANGEINFO, info)
        cmd, rinfo=self.socket.recv()
        self.setInfo(rinfo)
        return cmd, rinfo
    
    def updateData(self, data):
        '''转发更新数据到远程客户端，无返回'''
        self.socket.send(UPDATEDATA, data)
        return
    
    def resetData(self):
        '''重置游戏数据为初始状态，需重置ready状态，需转发到客户端'''
        super(NetPlayer, self).resetData()
        self.setReady(False)
        self.socket.send(RESETDATA)

if __name__ == '__main__':
    pass

